Skip to content

feat: add two-layer duplicate code detection to PR check (#42)#46

Merged
kenjudy merged 9 commits into
mainfrom
42-add-two-layer-duplicate-code-detection-to-pr-check
Jun 12, 2026
Merged

feat: add two-layer duplicate code detection to PR check (#42)#46
kenjudy merged 9 commits into
mainfrom
42-add-two-layer-duplicate-code-detection-to-pr-check

Conversation

@kenjudy

@kenjudy kenjudy commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds Layer 1 static duplicate detection via jscpd (always-on, zero token cost): runs on every PR against changed production files, posts a ## Duplicate Code section in the PR comment when findings exist
  • Adds Layer 2 semantic duplicate detection via Claude (conditional on ANTHROPIC_API_KEY): scopes analysis to changed files plus their direct module neighbors, finds structural similarity that token-level matching misses
  • All four detection thresholds configurable in lib/config.js so teams using this on other repos (Java, Python, Go) can tune without touching library code

New files

  • lib/duplicate.jsrunDuplicateCheck(filePaths) and resolveModuleNeighbors(filePaths)
  • __tests__/duplicate.test.js — 9 tests covering both functions
  • __tests__/config.test.js — 4 tests for new config key defaults

Changed files

  • lib/claude.js — adds analyzeDuplicatesWithClaude(client, filePaths, staticFindings)
  • lib/config.js — adds DUPLICATE_MIN_LINES, DUPLICATE_MIN_TOKENS, DUPLICATE_IGNORE_PATTERNS, DUPLICATE_SCAN_PATHS
  • .github/workflows/pr-metrics.yml — integrates both layers; PR comment shows static findings, semantic findings, and a layer indicator
  • CLAUDE.md — documents the four config keys; includes threshold tuning examples for Java, Python, and Go

Test plan

  • 150 tests passing, 13 suites, no regressions
  • Coverage: 96.29% lines, 96.66% functions (thresholds: 80% / 90%)
  • Grep audit confirms both layer indicator strings present in YAML and Layer 2 guarded by ANTHROPIC_API_KEY check
  • runDuplicateCheck([]) returns [] without calling jscpd
  • resolveModuleNeighbors skips non-JS files, deleted files, and external imports
  • analyzeDuplicatesWithClaude(null, ...) returns [] without calling the API

🤖 Generated with Claude Code

kenjudy and others added 9 commits June 9, 2026 11:15
Adds DUPLICATE_MIN_LINES (5), DUPLICATE_MIN_TOKENS (50),
DUPLICATE_IGNORE_PATTERNS ([]), and DUPLICATE_SCAN_PATHS ([]) to CONFIG.
All four keys are configurable so teams using this on other repos can
tune thresholds without touching library code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Layer 1 static duplicate detection: runs jscpd via child_process,
reads the JSON report it writes to a temp dir, and returns a structured
array of {firstFile, secondFile, lines, tokens}. Returns empty array on
empty input, missing report file, or non-zero jscpd exit — no throws.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parses require()/import statements in JS/TS files, resolves relative
paths to absolute, and returns the union of changed files plus their
direct local imports. Non-JS files are passed through without parsing;
files not on disk and external/node_modules imports are skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds analyzeDuplicatesWithClaude(client, filePaths, staticFindings)
which reads file contents, passes them to Claude with a duplication-
focused system prompt, and returns structured findings with file1/file2/
similarity/concern/confidence. Degrades to [] when client is null or
the API response is malformed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runs runDuplicateCheck against PR production files after checkout.
Adds a 'Duplicate Code' section to the PR comment when findings exist,
showing file:start-end pairs with line/token counts (capped at 10).
Section is omitted silently when jscpd finds no duplicates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Layer 2 semantic duplicate detection when ANTHROPIC_API_KEY is
set. Uses resolveModuleNeighbors to scope analysis to changed files
plus their direct imports, then passes results to analyzeDuplicatesWithClaude.
PR comment Duplication section now shows static findings, semantic
findings (when found), and a layer indicator confirming which layers ran.
Degrades to Layer 1 only when API key is absent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…set.sh

Uses PDCA_SKILL_DIR environment variable instead of an absolute path,
with a guard that warns and skips the install if the directory is absent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds four DUPLICATE_* keys to the configuration table with defaults
and descriptions. Includes a tuning guide with example overrides for
Java, Python, and Go repos where boilerplate inflates false positives.
Updates the pr-metrics.yml architecture description to reflect the
lib/duplicate.js and lib/claude.js dependencies added in this cycle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kenjudy kenjudy linked an issue Jun 12, 2026 that may be closed by this pull request
@github-actions

Copy link
Copy Markdown

PR Analysis

Size: large (based on production code)
Production Code: 299 lines (8 files)
Test Code: 178 lines (3 files)
Total: 477 lines (11 files)
Test-to-Production Ratio: 0.60:1

Concerns

  • Large production changes - review carefully
  • Median net additions ratio 0.93 exceeds 0.50 - possible batch-acceptance pattern

Strengths

  • Incremental development pattern detected
  • Includes refactoring or cleanup work
  • Message quality 100% meets discipline threshold

Commit Analysis

Total Commits: 9
Average Commit Size: 37 production lines
Average Files per Commit: 2.4

Metric Value
Large commits (>100 prod lines) 0/9 (0%)
Sprawling commits (>5 files) 0/9 (0%)
Test-first discipline 4/9 (44%)
Message quality 9/9 (100%)
Median net additions ratio 0.93
Test-only commits 0
Production-only commits 5

Commit Details

c33afd6 Ken Judy (6/9/2026)
refactor: add duplicate detection config keys to lib/config.js
84 prod lines, 3 files [test+prod]

9bce469 Ken Judy (6/9/2026)
feat: implement runDuplicateCheck in lib/duplicate.js
50 prod lines, 3 files [test+prod]

ebc9063 Ken Judy (6/12/2026)
feat: implement resolveModuleNeighbors in lib/duplicate.js
33 prod lines, 4 files [test+prod]

bf1eac4 Ken Judy (6/12/2026)
feat: add semantic duplicate detection via lib/claude.js
58 prod lines, 3 files [test+prod]

13e2db9 Ken Judy (6/12/2026)
feat: integrate jscpd findings into pr-metrics.yml PR comment
19 prod lines, 2 files

23664a6 Ken Judy (6/12/2026)
feat: integrate semantic findings into pr-metrics.yml
40 prod lines, 2 files

d320a65 Ken Judy (6/12/2026)
chore: replace hardcoded PDCA skill path with env var in demo/temp-reset.sh
10 prod lines, 2 files

d601314 Ken Judy (6/12/2026)
docs: update CLAUDE.md with duplicate detection config parameters
27 prod lines, 1 files

d5d839c Ken Judy (6/12/2026)
chore: sync beads task state after PDCA cycle completion
16 prod lines, 2 files

Test Coverage

Test Adequacy: good

  • Good balance of production and test code

Target ratio: 0.5-2.0 test lines per production line

DORA Capability Assessment

Archetype: mixed-signals
No clear archetype pattern. Review individual metric thresholds.

Capability Metric Value Target
Small Batches Large commit % 0% <20%
Small Batches Sprawling commit % 0% <10%
Version Control Test-first discipline 44% >50%
Version Control Message quality 100% >60%
AI Risk Signal Net additions ratio (median) 0.93 <0.50

Duplicate Code

Found 1 duplicate block(s) across the changed files:

  • lib/claude.js:85-91 duplicates lib/claude.js:142-148 (7 lines, 64 tokens)
    Layer 1 (static) ran. Set ANTHROPIC_API_KEY to enable semantic analysis.
    Automated by Code Metrics Workflow

@kenjudy
kenjudy merged commit 986ee9f into main Jun 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add two-layer duplicate code detection to PR check

1 participant